package com.yunxi.service.localService.vehicle.impl;

import com.yunxi.bizToBaseData.pojo.VehicleEngineeringConfig;
import com.yunxi.core.service.ServiceImplPlus;
import com.yunxi.dao.vehicle.VehicleConfigMapper;
import com.yunxi.model.vehicle.VehicleConfig;
import com.yunxi.service.localService.vehicle.VehicleConfigService;
import com.yunxi.vehicle.pojo.VehicleConfigFeatureVO;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;

import com.yunxi.vehicle.pojo.VehicleConfigInOutColorQueryReqVO;
import com.yunxi.vehicle.pojo.VehicleConfigInOutColorQueryRespVO;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

@Service
public class VehicleConfigServiceImpl extends ServiceImplPlus<VehicleConfigMapper, VehicleConfig> implements
    VehicleConfigService {

    @Override
    public List<VehicleConfigFeatureVO> findConfigFeatureByFamilyCode(String familyCode) {
        return baseMapper.selectConfigFeatureByFamilyCode(familyCode);
    }

    @Override
    public boolean delAll() {
        return baseMapper.delete(null) > 0;
    }

    @Override
    public void callPInitProduct() {
         baseMapper.callPInitProduct();
    }

    /**
     * 根据15位码颜色查询 车型默认工程配置
     * @param vehicleCode 15位码
     * @param inCode 内饰
     * @param outCode 外饰
     * @param customPackCode 选装包
     * @param allConfigMap 全量配置 Map<key:特征值, value:特征族>
     * @return Map<key:特征族, value:特征值>
     */
    @Override
    public Map<String, String> loadEngineeringConfigByVehicleCode(String vehicleCode, String inCode, String outCode,
        String customPackCode, Map<String, String> allConfigMap) {
        // 单车默认配置MAP,<key:特征族,value:特征值>
        List<VehicleEngineeringConfig> configs = baseMapper.loadEngineeringConfigByVehicleCode(vehicleCode);
        Map<String, String> configMap = new HashMap<>();
        configs.forEach(
            engineeringConfig -> configMap.put(engineeringConfig.getFamilyCode(), engineeringConfig.getFeatureCode()));

        // 颜色
        configMap.put("NNN", inCode);
        configMap.put("WWW", outCode);

        // 选装包
        if (!StringUtils.isEmpty(customPackCode)) {
            String[] packageCodes = customPackCode.split(",");
            for (String code : packageCodes) {
                if (!StringUtils.isEmpty(code)) {
                    configMap.put(allConfigMap.get(code), code);
                }
            }
        }
        return configMap;
    }

    /**
     * 查询全量工程配置
     *
     * @return 工程配置集合
     */
    @Override
    public Map<String, String> loadAllEngineeringConfig() {
        List<VehicleEngineeringConfig> allConfig = baseMapper.loadAllEngineeringConfig();
        Map<String, String> allConfigMap = new HashMap<>();
        allConfig.forEach(engineeringConfig -> allConfigMap
            .put(engineeringConfig.getFeatureCode(), engineeringConfig.getFamilyCode()));
        return allConfigMap;
    }

    /**
     * 校验单车配置是否满足条件
     *
     * @param condition 条件
     * @param configMap 单车配置 Map<key:特征族,value:特征值>
     * @return true or false
     */
    @Override
    public boolean checkIsMeet(String condition, Map<String, String> configMap) {
        return checkPriorityFormula(condition, configMap);
    }

    /**
     * BOM内饰配置
     * @param vo
     * @return
     */
    @Override
    public List<VehicleConfigInOutColorQueryRespVO> queryVehicleConfigInColorByApp(VehicleConfigInOutColorQueryReqVO vo) {
        List<VehicleConfigInOutColorQueryRespVO> result1 = this.baseMapper.queryVehicleConfigInColorByApp(vo);
        return result1;
    }

    /**
     * BOM内饰配置
     * @param vo
     * @return
     */
    @Override
    public List<VehicleConfigInOutColorQueryRespVO> queryVehicleConfigOutColorByApp(VehicleConfigInOutColorQueryReqVO vo) {
        List<VehicleConfigInOutColorQueryRespVO> result1 = this.baseMapper.queryVehicleConfigOutColorByApp(vo);
        return result1;
    }

    /**
     * 校验单车配置是否满足公式
     *
     * @param formula 公式
     * @param configMap 单车配置 Map<key:特征族,value:特征值>
     * @return 子公式
     */
    private static Boolean checkPriorityFormula(String formula, Map<String, String> configMap) {
        String priorityFormula = formula; // 需要计算的公式
        String subFormula = formula;// 子公式
        // 如果包含括号，先分解出优先执行的子公式
        if ((formula.contains("[") && formula.contains("]")) || (formula.contains("(") && formula.contains(")"))) {
            priorityFormula = getPriorityFormula(formula);
            subFormula = priorityFormula.replace("(", "").replace(")", "");
        }

        // 校验公式单车是否满足子公式
        String subResult = checkSubFormula(subFormula, configMap);
        // 用计算结果替换子公式字符串
        formula = formula.replace(priorityFormula, subResult);
        // 当公式最终替换成"true"或"false"时结束
        if ("true".equals(formula) || "false".equals(formula)) {
            return Boolean.valueOf(formula);
        }
        System.out.println(formula);
        return checkPriorityFormula(formula, configMap);
    }


    /**
     * 返回最优先执行的式子
     *
     * @param formula 公式
     * @return 子公式
     */
    private static String getPriorityFormula(String formula) {
        Stack<Character> stack = new Stack<>();
        int start = -1;
        for (int i = 0; i < formula.length(); i++) {
            switch (formula.charAt(i)) {
                case '[':
                case '(':
                    start = i;
                    stack.push(formula.charAt(i));
                    break;
                case ')':
                    //若前一个元素刚好匹配则出栈
                    if (stack.peek().toString().charAt(0) == '(') {
                        stack.pop();
                        return formula.substring(start, i + 1);
                    }
                    break;
                case ']':
                    //若前一个元素刚好匹配则出栈
                    if (stack.peek().toString().charAt(0) == '[') {
                        stack.pop();
                        return formula.substring(start, i + 1);
                    }
                    break;
                default:
            }
        }
        return formula;
    }


    /**
     * 校验公式单车是否满足公式
     *
     * @param formula 公式
     * @param configMap 单车配置
     * @return 结果 "true" or "false"
     */
    private static String checkSubFormula(String formula, Map<String, String> configMap) {
        String b = "true";
        if (formula.contains("&")) {
            List<String> and = new ArrayList<>(Arrays.asList(formula.split("&")));
            if (and.contains("false")) {
                b = "false";
            } else {
                for (String code : and) {
                    if (!"true".equals(code) && !configMap.containsValue(code)) {
                        b = "false";
                    }
                }
            }
        } else if (formula.contains("|")) {
            b = "false";
            List<String> or = new ArrayList<>(Arrays.asList(formula.split("\\|")));
            if (or.contains("true")) {
                b = "true";
            } else {
                for (String code : or) {
                    if (!"false".equals(code) && configMap.containsValue(code)) {
                        b = "true";
                    }
                }
            }
        } else if(!configMap.containsValue(formula)){
            b = "false";
        }
        return b;
    }


}
